package listeners

import (
	"blockchains-aio/conf"
	"blockchains-aio/db"
	"blockchains-aio/stack"
	"blockchains-aio/util"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"os"
	"strconv"
)

func RegisterStack3(router *gin.Engine) {
	router.MaxMultipartMemory = 8 << 10 // 8 KB

	rootGroup := getRootGroup(router)

	//-----bft3 consensus as followed
	rootGroup.POST("/stack2/tmpl/bft3", doGenStack2ConfigForBft3)
	rootGroup.POST("/stack2/bft3", doDockStack2DeployForBft3)

}

// curl -X POST  -F "file=@/path/to/file.txt" -d "chainname=创建链名&nodeNum=节点数量" http://localhost:39781/blockchainsaio/stack2/bft3
func doDockStack2DeployForBft3(ctx *gin.Context) {
	chainname := ctx.PostForm("chainname")
	nodeNumStr := ctx.PostForm("nodeNum")
	consensus := ctx.PostForm("consensus")
	consensus = "bft3"

	log.Printf("recieved {chainname: %s,consensus: %s,nodeNum: %s}", chainname, consensus, nodeNumStr)
	nodeNum, err := strconv.Atoi(nodeNumStr)
	if err != nil {
		ctx.JSON(400, fmt.Sprintf("nodeNum is not number: %s", nodeNumStr))
		return
	}

	if len(chainname) == 0 {
		ctx.JSON(400, fmt.Sprintf("Failed to get chainname"))
		return
	}

	file, _ := ctx.FormFile("file")
	f, err := file.Open()
	if err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to open yaml:%v", err))
		return
	}
	defer f.Close()

	p := make([]byte, file.Size)
	if _, err := f.Read(p); err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to read yaml: %v", err))
		return
	}

	//if err := stack.CopyDirs_BFT2(chainname, consensus); err != nil {
	//	ctx.JSON(400, fmt.Sprintf("Failed to copy necessary files: %v", err))
	//	return
	//}

	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chainname)
	yaml := chainFolder + "/" + conf.DefaultComposeFileName

	if err := util.CreateAllDir(chainFolder); err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to create chain folder %s: %v", chainFolder, err))
		return
	}

	if err := os.WriteFile(yaml, p, 0644); err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to write running config file %s: %v", yaml, err))
		return
	}

	log.Printf(fmt.Sprintf("working directory: %s", chainFolder))
	out, err := util.DockerComposeDeployUp3(chainFolder)
	if err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to deploy compose task: %v", err))
		return
	}

	if err = db.CreateStack(chainname, consensus, string(p), nodeNum); err != nil {
		ctx.JSON(http.StatusBadRequest, fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), nodeNum, err))
		return
	}

	ctx.JSON(200, out.String())
}

// curl -X POST -d '{"ConfigTmpl":"","Chaincode":"","Chainname":"bft3chain","Peers":[{"Name":"peer0","CliName":"cli0","PortMappings":[{"Target":8051,"Destination":8051},{"Target":8052,"Destination":8052},{"Target":8053,"Destination":8053}]},{"Name":"peer1","CliName":"cli1","PortMappings":[{"Target":18051,"Destination":8051},{"Target":18052,"Destination":8052},{"Target":18053,"Destination":8053}]}]}' http://localhost:39781/blockchainsaio/stack2/tmpl/bft3
func doGenStack2ConfigForBft3(ctx *gin.Context) {
	var bft3Config stack.BFT3
	//consensus := ctx.GetHeader("Consensus-Template-Type")

	if err := ctx.BindJSON(&bft3Config); err != nil {
		ctx.JSON(http.StatusBadRequest, err)
		return
	}
	bft3Config.ConfigTmpl = conf.GetStackTemplateResFolder("bft3")
	bft3Config.Chaincode = fmt.Sprintf("%s/%s", conf.GetNfsFolder(), bft3Config.Chainname)

	bft3Tmpl := fmt.Sprintf("%s/%s.tmpl", conf.GetStackTemplateFolder(), "bft3")
	err := stack.ParsePFT3Template(ctx.Writer, bft3Tmpl, bft3Config)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, fmt.Sprintf("%v", err))
	}
}

func cleanIfPossible(ns3ExeFolder, chainFolder string) error {
	composeYml := fmt.Sprintf("%s/%s", chainFolder, "compose.yml")

	if !util.IsPathExists(composeYml) {
		return nil
	}

	out, err := util.Ns3Sh(ns3ExeFolder, "0", true)
	if err != nil {
		log.Println(out.String())
		return err
	}

	return os.RemoveAll(chainFolder)
}
